#ifndef GENERATED_DATA_HPP
#define GENERATED_DATA_HPP

#include "sdk_config.h"
#include "content/bindable.hpp"

#include <memory>
#include <optional>

#if defined(__CODEGEN__)
#define PTYPE(tag,name,...) tag __attribute__((annotate("TYPE;" __VA_OPT__(#__VA_ARGS__)))) name
#define PMETA(...) __attribute__((annotate("META;" __VA_OPT__(#__VA_ARGS__))))
#else
#define PTYPE(tag,name,...) tag name
#define PMETA(...)
#endif

#define PCLASS(name, ...)  PTYPE(class, name, ## __VA_ARGS__)
#define PSTRUCT(name, ...) PTYPE(struct,name, ## __VA_ARGS__)

namespace CodeGen {
    template <typename T> struct bind_helper;
    using bindable_ptr = std::unique_ptr<bindable_base>;
}

template <typename T>
concept has_prev_get = requires (T t, const std::string &key, bool *handled) {
    { t.prev_get(key, handled) } -> std::same_as<bindable_base::binddata_t>;
};

template <typename T>
concept has_post_get = requires (T t, const std::string &key, bool *handled) {
    { t.post_get(key, handled) } -> std::same_as<bindable_base::binddata_t>;
};

template <typename T>
inline bindable_base::binddata_t do_prev_get(T &, const std::string &, bool *ok) { *ok = false; return {}; }

template <has_prev_get T>
inline bindable_base::binddata_t do_prev_get(T &t, const std::string &key, bool *ok) { *ok = false; return t.prev_get (key, ok); }

template <typename T>
inline bindable_base::binddata_t do_post_get(T &, const std::string &, bool *ok) { *ok = false; return {}; }

template <has_post_get T>
inline bindable_base::binddata_t do_post_get(T &t, const std::string &key, bool *ok) { *ok = false; return t.post_get(key, ok); }

#define GENERATED_GET_DATA(cls_name) \
private: \
    friend struct ::CodeGen::bind_helper<cls_name>; \
    PMETA(Skipped) static bindable_base *create_binddata(cls_name *inst); \
    PMETA(Skipped) ::CodeGen::bindable_ptr bind_store{}; \
public: \
    PMETA(Skipped) inline bindable_base *get_bindable() { \
        struct init_guard { init_guard(cls_name *inst) { inst->bind_store = ::CodeGen::bindable_ptr{create_binddata(inst)}; } }; \
        static init_guard init_{this}; \
        return bind_store.get(); \
    }

#include "content/data_helper.hpp"

#endif // GENERATED_DATA_HPP
